import { Injectable } from '@nestjs/common';
import { CreateRoleDto } from './dto/create-role.dto';
import { UpdateRoleDto } from './dto/update-role.dto';
import { BusinessException } from '@/common';
import { IPaginationOptions, paginate } from 'nestjs-typeorm-paginate';
import { Menu } from '../menu/entities/menu.entity';
import { Role } from './entities/role.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { Between, FindOptionsWhere, In, Like, Repository } from 'typeorm';
import { roleQueryVo } from '@/common/interface';

@Injectable()
export class RoleService {
  constructor(
    @InjectRepository(Role) private readonly roleRepository: Repository<Role>
  ) {}

  findOneByName(name: string) {
    return this.roleRepository.findOne({
      where: { name }
    });
  }

  async create(createRoleDto: CreateRoleDto) {
    // 检查角色是否存在
    const hasRole = await this.findOneByName(createRoleDto.name);
    if (hasRole) {
      throw new BusinessException({ code: 400, message: '角色已存在' });
    }

    // 角色实体
    const role = new Role();
    ['name', 'mark', 'desc', 'status'].forEach((v) => {
      role[v] = createRoleDto[v];
    });

    // 关联菜单
    if (createRoleDto?.menus?.length > 0) {
      const menus = createRoleDto.menus.map((item) => {
        const menu = new Menu();
        menu.id = item.id;
        return menu;
      });
      role.menus = menus;
    }

    return this.roleRepository.save(role);
  }

  findAll(options: IPaginationOptions, roleQuery: roleQueryVo) {
    const { name, queryDate } = roleQuery;
    const where: FindOptionsWhere<Role> = {};
    if (name) {
      where.name = Like(`%${name}%`);
    }

    if (queryDate?.length) {
      where.createdAt = Between(queryDate[0], queryDate[1]);
    }

    return paginate(this.roleRepository, options, {
      where
    });
  }

  findOne(id: number) {
    return this.roleRepository.findOne({
      where: {
        id
      },
      relations: ['menus'] // 关联菜单和用户
    });
  }

  async update(updateRoleDto: UpdateRoleDto) {
    // 角色实体
    const role = new Role();
    ['id', 'name', 'mark', 'desc', 'status'].forEach((k) => {
      role[k] = updateRoleDto[k];
    });

    // 关联菜单
    if (updateRoleDto?.menus?.length > 0) {
      const menus = updateRoleDto.menus.map((item) => {
        const menu = new Menu();
        menu.id = item.id;
        return menu;
      });
      role.menus = menus;
    }

    return this.roleRepository.save(role);
  }

  remove(id: number) {
    return this.roleRepository.delete(id);
  }

  changeStatus(id: number, status: number) {
    return this.roleRepository.update(id, { status });
  }

  findByIds(roleIds: number[]) {
    return this.roleRepository.find({
      where: {
        id: In(roleIds)
      },
      relations: ['menus']
    });
  }
}
